# @Version        : 1.0
# @Update Time    : 2024/9/10 21:16
# @File           : base_schema.py
# @IDE            : PyCharm
# @Desc           : 文件描述信息
from typing import Callable, Any

from fastapi_utils.api_model import APIModel

from src.common.typing.schema_typing import DatetimeStr
from pydantic import WrapValidator
from pydantic_core import PydanticCustomError
from pydantic_core.core_schema import ValidationInfo, ValidatorFunctionWrapHandler


class MixinSchema(APIModel):
    id: int | None = None
    created_at: DatetimeStr | None = None
    updated_at: DatetimeStr | None = None


def custom_error_msg(msg: str = None) -> WrapValidator:
    """
    针对Filed进行封装
    :param msg:
    :return:
    """

    def _validator(v: Any, next_: Any, ctx: ValidationInfo) -> Any:
        try:
            return next_(v, ctx)
        except Exception as e:
            _msg = msg if msg else str(e)
            raise PydanticCustomError("custom_error", _msg) from None

    return WrapValidator(_validator)


class FieldValidator:
    """
    自定义校验
    捕获 ValueError 和 AssertionError 异常的 WrapValidator 和
    引发 PydanticCustomError，并显示原始异常的消息，
    pydantic验证异常输出的错误信息对用户不友好
    """

    def __new__(
        cls, validator: Callable[[Any], None], msg: str = "参数校验异常"
    ) -> WrapValidator:
        """
        使用 WrapValidator 包装验证函数来捕获 ValueError 和
        AssertionError 异常并引发 PydanticCustomError 消息
        从原始异常中移除错误类型前缀，即
        不方便用户使用。

        :param validator: 要包装的验证器函数。
        :returns: 美化错误消息的 WrapValidator 实例。
        """

        def _validator(
            v: Any, handler: ValidatorFunctionWrapHandler, _: ValidationInfo
        ):
            try:
                validator(v)
            except (ValueError, AssertionError) as exc:
                raise PydanticCustomError(
                    "custom_error",
                    str(exc),
                )
            except Exception:
                raise PydanticCustomError(
                    "custom_error",
                    msg,
                )
            return handler(v)

        return WrapValidator(_validator)
